
import styles from './voiceCombine.module.scss';
import { useState, useEffect, useCallback, useRef } from 'react';
import { InputNumber, Image, Slider, Select, Dropdown, Radio, Checkbox, Message, Input } from '@arco-design/web-react';
import editIcon from '@/assets/images/audio/edit_icon.svg';
import scaleUp from '@/assets/images/audio/scale_up.svg';
import scaleDown from '@/assets/images/audio/scale_down.svg';
import playIcon from '@/assets/images/audio/play_icon.svg';
import pausedIcon from '@/assets/images/audio/paused_icon.svg';
import cursor from '@/assets/images/audio/cusor.svg';
import micIcon from '@/assets/images/audio/mic_icon.svg';
import MlsAudio from '@/components/common/mlsAudio';
import { alignVoicePeak, reMergeAudios } from '@/api/audio';
import { useLoading } from '@/components/common/mlsLoading/laodingText';
import sharedWebSocket from '@/services/sharedWebSocket.jsx';

export default function VoiceCombine({ onNextStep, audioList, setMergedAudioList }) {
  const [time, setTime] = useState(600)
  const [inputKey, setInputKey] = useState(0);
  // 创建一个角色名称数组，确保每个元素都有初始值
  const [roleNames, setRoleNames] = useState([]); // 片段可选角色
  const [rolesColor, setRolesColor] = useState({}); // 片段对应颜色
  const [currentAudio, setCurrentAudio] = useState(''); // 当前麦克风
  const colors = ['roles1', 'roles2', 'roles3', 'roles4', 'roles5', 'roles6'] // 颜色class
  const timeLineRef = useRef(null); // 音频时间轴
  const audioRef = useRef(null);
  const [duration, setDuration] = useState(0);
  const [currentTime, setCurrentTime] = useState(0);
  const [isLoading, setIsLoading] = useState(false);
  const [isPlaying, setIsPlaying] = useState(false);
  const [isDragging, setIsDragging] = useState(false); // 新增：追踪拖动状态
  const animationFrameRef = useRef(null);
  const lastUpdateTimeRef = useRef(0);
  const [scale, setScale] = useState(0.5);
  const [separateVoice, setSeparateVoice] = useState(false);
  const { showLoading, hideLoading } = useLoading();
  const [isSelectAudio, setIsSelectAudio] = useState({});
  const dropdownRef = useRef(null);
  const [reSet, setReSet] = useState(false);

  useEffect(() => {
    const handleOpt = data => {
      console.log('scoket: ', data);
      if (data.func === 'peak_alignment_success') {
        hideLoading();
        onNextStep(data.data)
      }
      if (data.func === 'peak_alignment_fail') {
        hideLoading();
        Message.error(data?.message || '对齐失败');
      }
    };
    sharedWebSocket.on('resp', handleOpt);
    return () => {
      sharedWebSocket.off('resp', handleOpt);
    };
  }, []);

  useEffect(() => {
    function handleClickOutside(e) {
      if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
        setIsSelectAudio({})
      }
    }
    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, []);

  const scaleRef = useRef(scale);
  useEffect(() => {
    scaleRef.current = scale;
  }, [scale])

  useEffect(() => {
    if(audioList && audioList.length > 0) {
      if(!currentAudio) {
        setCurrentAudio({...audioList[0]})
        let roles = (audioList[0].audioList || []).filter(item => item.selectAudioList).map(item=>item.roleName);
        let obj = {};
        [...new Set(roles)].forEach((item, index) => {
          obj[item] = colors[index]
        });
        setRolesColor(obj);
        setRoleNames([...new Set(roles)]);
      }else {
        setReSet(false);
        audioList.forEach(item => {
          if(item.micType == currentAudio.micType) {
            setCurrentAudio({...item})
          }
        })
      }
    }
  }, [audioList])

  // 调整进度更新逻辑，考虑拖动状态
  const updateProgressSmoothly = useCallback(() => {
    const audio = audioRef.current;
    if (!audio || !isPlaying || isDragging) return; // 拖动时暂停自动更新

    const now = Date.now();
    // 限制更新频率，但使用requestAnimationFrame保持视觉流畅
    if (now - lastUpdateTimeRef.current > 50) {
      // 大约20fps
      setCurrentTime(audio.currentTime);
      lastUpdateTimeRef.current = now;
    }

    // 继续请求下一帧
    animationFrameRef.current = requestAnimationFrame(updateProgressSmoothly);
  }, [isPlaying, isDragging]);

  // 新增：在播放状态变化时控制动画帧请求
  useEffect(() => {
    if (isPlaying) {
      updateProgressSmoothly();
    } else if (animationFrameRef.current) {
      cancelAnimationFrame(animationFrameRef.current);
    }

    return () => {
      if (animationFrameRef.current) {
        cancelAnimationFrame(animationFrameRef.current);
      }
    };
  }, [isPlaying, updateProgressSmoothly]);

  // 初始化和监听音频事件
  useEffect(() => {
    const audio = audioRef.current;
    if (!audio) return;

    const handleLoadedMetadata = () => {
      setDuration(audio.duration);
    };

    // 新增：监听加载事件
    const handleLoadStart = () => {
      setIsLoading(true);
    };

    const handleCanPlayThrough = () => {
      setIsLoading(false);
    };

    // 新增：监听缓冲事件
    const handleProgress = () => {
      if (audio.buffered.length > 0) {
        const bufferedEnd = audio.buffered.end(audio.buffered.length - 1);
        const duration = audio.duration;
        // if (duration > 0) {
        //   setBufferedProgress((bufferedEnd / duration) * 100);
        // }
      }
    };

    const handleTimeupdate = (e) => {
      setCurrentTime(audio.currentTime);
    }

    // 新增：监听播放结束事件
    const handleEnded = () => {
      setIsPlaying(false);
      // onEnded();
    };

    audio.addEventListener('loadedmetadata', handleLoadedMetadata);
    audio.addEventListener('loadstart', handleLoadStart);
    audio.addEventListener('canplaythrough', handleCanPlayThrough);
    audio.addEventListener('progress', handleProgress);
    // audio.addEventListener('timeupdate', handleTimeupdate);
    audio.addEventListener('ended', handleEnded); // 新增：添加播放结束事件监听

    return () => {
      audio.removeEventListener('loadedmetadata', handleLoadedMetadata);
      audio.removeEventListener('loadstart', handleLoadStart);
      audio.removeEventListener('canplaythrough', handleCanPlayThrough);
      audio.removeEventListener('progress', handleProgress);
      // audio.addEventListener('timeupdate', handleTimeupdate);
      audio.removeEventListener('ended', handleEnded); // 新增：移除播放结束事件监听
    };
  }, []);

  // 播放/暂停切换
  const togglePlay = () => {
    const audio = audioRef.current;
    if (!audio) return;

    if (isPlaying) {
      audio.pause();
    } else {
      audio.play().catch(err => {
        console.error('播放失败:', err);
        setIsPlaying(false);
      });
    }
    setIsPlaying(!isPlaying);
  };

  const updateTime = (time) => {
    const audio = audioRef.current;
    if (!audio) return;
    setCurrentTime(time);
    audio.currentTime = time;
  }

  useEffect(() => {
    const handleWheel = (e) => {
      if(e.deltaY > 0) {
        if(scaleRef.current >= 64) {
          setScale(64)
        }else {
          setScale(scaleRef.current*2)
        }
      }else {
        if(scaleRef.current <= 0.5) {
          setScale(0.5)
        }else {
          setScale(scaleRef.current/2)
        }
      }
      e.preventDefault(); // 禁用页面滚动穿透
    };
    timeLineRef.current.addEventListener('wheel', handleWheel);
    return () => timeLineRef.current?.removeEventListener('wheel', handleWheel);
  }, []);

  // 打开音频选择弹框
  const toSelectAudio = (fragment, audioItem) => {
    if(audioItem.micType === currentAudio.micType) {
      let obj = {};
      obj[currentAudio.micType + '-' + fragment.startStamp] = !isSelectAudio[currentAudio.micType + '-' + fragment.startStamp];
      setIsSelectAudio(obj);
    }else {
      setIsSelectAudio({});
    }
  } 
  // 切换片段音频
  const changeAudio = (value, fragment, audioSelect) => {
    setIsSelectAudio({});
    let audioArr = [];
    let audioUrls = [];
    audioList.forEach(item => {
      if(item.micType === currentAudio.micType) {
        let tempItem = {...item, audioList: [...item.audioList]};
        let tempAudioList = [];
        tempItem.audioList.forEach(audio => {
          if(audio.startStamp === fragment.startStamp) {
            let selectAudioList = JSON.parse(JSON.stringify(audio.selectAudioList));
            let newSelectAudioList = [];
            (selectAudioList || []).forEach(seletcAudio => {
              if(seletcAudio.audioName === audioSelect.audioName) {
                newSelectAudioList.push({...seletcAudio, audioName: audio.audioName, audioUrl: audio.audioUrl});
              }else {
                newSelectAudioList.push({...seletcAudio});
              }
            });
            audioUrls.push(audioSelect.audioUrl)
            tempAudioList.push({...audio, audioName: audioSelect.audioName, audioUrl: audioSelect.audioUrl});
          }else {
            audioUrls.push(audio.audioUrl)
            tempAudioList.push({...audio});
          }
        })
        audioArr.push({...tempItem, audioList: tempAudioList});
      }else {
        audioArr.push({...item});
      }
    });
    showLoading("重新合并音频中...");
    reMergeAudios({audioUrls}).then(res => {
      hideLoading();
      if(res.code === 200) {
        audioArr.forEach(item => {
          if(item.micType === currentAudio.micType) {
            item.wholeAudioUrl = res.data
          }
        })
        setMergedAudioList(audioArr);
      }
    });
  }

  const setDropList = (fragment) => (
    <div className={styles.selectAudioList} ref={dropdownRef}>
      {(fragment.selectAudioList || []).map((audio, index) => (
        <div key={index} className={styles.rolesItem}>
          <Radio defaultChecked={false} onChange={(value) => { changeAudio(value, fragment, audio) }}></Radio>
          <MlsAudio progressHeight={20} title={audio.audioName} showTime={false} src={audio.audioUrl} showVolumeControl={false} showELseControl={false}></MlsAudio>
        </div>
      ))}
    </div>
  )

  const formatTime = (time) => {
    if(time) {
      let min = String(Math.floor(time/60))
      let sec = String(Math.round(time%60))
      return (min.length < 2?('0' + min):min) + ':' + (sec.length < 2?('0' + sec): sec)
    }
    return '00:00'
  }

  const fomatMsTime = (seconds, isTrue = true) => {
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const secs = Math.floor(seconds % 60);
    const ms = isTrue?Math.floor(Math.round(seconds * 1000 % 1000)):Math.floor((seconds * 100 % 100) * 10);
    return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')},${ms.toString().padStart(3, '0')}`;
  }

  // 切换片段说话人
  const changeRoles = (value, fragment) => {
    let audioArr = [];
    audioList.forEach(item => {
      if(item.micType === currentAudio.micType) {
        let tempItem = {...item, audioList: [...item.audioList]};
        let tempAudioList = [];
        tempItem.audioList.forEach(audio => {
          if(audio.startStamp === fragment.startStamp) {
            tempAudioList.push({...audio, roleNameModified: value})
          }else {
            tempAudioList.push({...audio})
          }
        })
        audioArr.push({...tempItem, audioList: tempAudioList})
      }else {
        audioArr.push({...item})
      }
    });
    setMergedAudioList(audioArr);
  }

  // 切换麦克风
  const changeMic = (audioItem) => {
    setCurrentAudio({...audioItem})
  }

  const toAlignPeak = () => {
    let micList = [];
    audioList.forEach(item => {
      let obj = {
        micType: item.micType,
        originalAudioList: [...item.originalAudioList],
        audioList: []
      };
      item.audioList.forEach(audio => {
        let temp = {...audio, roleNameModified: audio.roleNameModified || audio.roleName, startStamp: fomatMsTime(audio.startStamp), endStamp: fomatMsTime(audio.endStamp)};
        obj.audioList.push(temp);
      });
      micList.push(obj);
    })
    let params = {
      separateVoice,
      micList,
    };
    alignVoicePeak(params).then(res => {
      if(res.code !== 200) {
        Message.error("操作失败！")
      }else {
        showLoading('对齐中...');
      }
    }).catch(error => {
      Message.error("操作异常！")
    })
  }

  const roleChangeSet = (e, oldName) => {
    let newName = e.target.value.trim();
    if(newName === oldName) {
      return
    }

    if(!newName) {
      Message.error("角色名称不能为空！")
      return
    }

    let isExist = roleNames.find(item => { return item === newName });
    if(isExist) {
      setInputKey((prevKey) => prevKey + 1);
      Message.error("已存在同名角色名！")
      return
    }

    setReSet(true);
    // 遍历更新角色名
    let newAudioList = [];
    audioList.forEach(item => {
      let tempItem = {...item}
      let newItemAudioList = [];
      item.audioList.forEach(audio => {
        let temp = {...audio};
        if(audio.roleNameModified && audio.roleNameModified === oldName) {
          temp.roleNameModified = newName;
        } else {
          if(audio.roleName === oldName) {
            temp.roleNameModified = newName;
          }
        }
        newItemAudioList.push(temp);
      });
      tempItem.audioList = newItemAudioList
      newAudioList.push(tempItem);
    })

    // 更新角色及角色对应颜色
    let newRoleNames = [];
    let newRoleColors = {};
    roleNames.forEach(role => {
      if(role === oldName) {
        newRoleColors[newName] = rolesColor[role];
        newRoleNames.push(newName);
      }else {
        newRoleColors[role] = rolesColor[role];
        newRoleNames.push(role);
      }
    })
    setRoleNames(newRoleNames);
    setRolesColor(newRoleColors);
    setMergedAudioList(newAudioList);
  }
  return (
    <div className={styles.voiceCombine}>
      <div className={styles.voiceCombineTitle}>
        同期声制作-音频合并处理
      </div>
      <div className={styles.voiceCombineTools}>
          <div className={styles.roles}>
            <span className={styles.label}>角色数量</span>
            <span className={styles.rolesInput}>
              <InputNumber
                mode='button'
                defaultValue={roleNames.length}
                disabled={true}
                style={{ width: 200, height: 32, boxSizing: 'border-box' }} 
              />
              </span>
          </div>
          {roleNames.map((name, index) => (
            <div key={index + '-' + inputKey} className={`${styles.roleSelectItem} ${ index === 0 ?'firstRole': ''}`}>
              <div className={styles.roleTitle}>
                <div className={`${styles.roleIcon} ${rolesColor[name]}`}></div>
                <Input defaultValue={name} onBlur={(e) => { roleChangeSet(e, name) }}></Input>
              </div>
              <div className={styles.roleHandle}>
                <Image preview={false} draggable={false} src={editIcon}/>
              </div>
            </div>
          ))}
      </div>
      <div className={styles.voiceCombineTimeline}>
          <audio ref={audioRef} src={currentAudio.wholeAudioUrl} preload="metadata" />
          <div className={styles.timeLine}>
            <div className={styles.title}>
              <Image preview={false} draggable={false} src={isPlaying?pausedIcon:playIcon} width={33} height={33} onClick={() => togglePlay()}/>
            </div>
            <div className={styles.timeArea} ref={timeLineRef}>
              {
                Array.from({ length: Math.ceil(Math.max(Math.ceil(duration), 640)/scale) }).map((_, index) => (
                  <div className={styles.timeUnit} key={index} onClick={() => updateTime(index*scale)}>
                    { ((index===0) || ((index) % 4 === 0))? (<div>{(index === 0 ? 0: (index*scale)) + 's'}</div>): (<div style={{fontSize: '2px'}}>・</div>) }
                  </div>
                ))
              }
            </div>
            <div className={styles.cursor} style={{transition: 'left 0.3s ease', left: ((currentTime*40)/scale + 206)}}>  
              <Image preview={false} draggable={false} src={cursor}/>
            </div>
          </div>
          <div className={styles.rolesList} style={{width: (Math.ceil(Math.ceil(duration)/scale) * 40 + 204) + 'px'}}>
          {audioList.map(audioItem => (
            <div key={audioItem.micType} className={`${styles.roleItem} ${audioItem.micType==currentAudio.micType?'is-active':""}`}>
              <div className={styles.title} onClick={() => { changeMic(audioItem) }}>
                <Image preview={false} draggable={false} src={micIcon}/>
                <div className={styles.roleName}>{audioItem.micType}</div>
                <div className={styles.currentTime}>{formatTime(currentTime)}</div>
              </div>
              <div className={styles.timeFragments} style={{width: (Math.ceil(Math.ceil(duration)/scale) * 40 + 4) + 'px'}}>
              {(audioItem.audioList || []).filter(item=> item.selectAudioList).map(fragment => (
                <div key={fragment.startStamp} className={`${styles.fragment} ${fragment.roleNameModified?rolesColor[fragment.roleNameModified]:rolesColor[fragment.roleName]}`} style={{width: ((Number(fragment.endStamp) - Number(fragment.startStamp))/scale)*40 + 'px', left: (Number(fragment.startStamp)/scale)*40 + 'px'}}>
                  <div className={styles.selectName}>
                    {(<Select
                      className={`${styles.select} ${styles.roleSelect}`}
                      value={fragment.roleNameModified || fragment.roleName}
                      onChange={(value) => { changeRoles(value, fragment) }}
                      placeholder="未指定"
                      disabled={audioItem.micType!==currentAudio.micType}
                      allowClear={false}>
                      {roleNames.map((name, index) => (
                        <Select.Option key={index} value={name} title={name}>
                          {name}
                        </Select.Option>
                      ))}
                    </Select>)}
                  </div>
                  <div className={styles.audioNum}>
                    <Dropdown droplist={setDropList(fragment)} popupVisible={!!isSelectAudio[audioItem.micType + '-' + fragment.startStamp]} disabled={fragment.selectAudioList.length === 0} trigger='click' position='bl' getPopupContainer={(node) => node.parentNode}>
                      <div className={styles.numText} onClick={ () => { toSelectAudio(fragment, audioItem) }}>
                        <div className={styles.text}>1</div>
                      </div>
                    </Dropdown>
                  </div>
                </div>
              ))}
              </div>
            </div>
          ))}
          </div>
      </div>
      <div className={styles.footerHandle}>
        <Checkbox className={styles.humanAudioSplit} defaultChecked={separateVoice} onChange={(value) => { setSeparateVoice(value) }}>人声分离</Checkbox>
        <div className={styles.startAlign} onClick={() => {
          toAlignPeak()
        }}>
          开始对齐
        </div>
      </div>
    </div>
  );
}